/*********************************************************************
 * Software License Agreement
 *
 * Copyright (C) 2010 Cross The Road Electronics.  All rights
 * reserved.
 *
 * Cross The Road Electronics (CTRE) licenses to you the right to 
 * use, copy, modify, merge, publish, distribute, sublicense, and/or 
 * sell copies of the Software ONLY when in use with CTRE's 2CAN 
 * Ethernet CAN Gateway.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * CROSS THE ROAD ELECTRONICS BE LIABLE FOR ANY INCIDENTAL, SPECIAL, 
 * INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
********************************************************************/
#include "stdafx.h"

#include "2CANClient.h"
#include "../Common/2CAN_DLL_API.h"
#include "../Common/NetComm/2CAN_DataObjects.h"

#include <iostream>
#include <stdio.h>
#include <map>

typedef std::map<uint32_t,P2CANClient> Handlemap_t;
Handlemap_t g_Handlemap;
uint32_t cntr = 1;

P2CANClient GetClient(uint32_t handle)
{
	Handlemap_t::iterator i = g_Handlemap.find(handle);
	if(i != g_Handlemap.end())
		return i->second;
	return 0;
}

ctr_error_t _stdcall CTR_Find2CAN(Found2Can * found2can,uint32_t options)
{
	if(found2can == 0)
		return ctr_badParameter;

	return C2CANClient::Find2Can(found2can,options);
}
ctr_error_t _stdcall CTR_Init(const char * ip,uint32_t * handle)
{
	*handle = cntr++;
	P2CANClient p = new C2CANClient();
	
	g_Handlemap[*handle] = p;
	ctr_error_t err = p->Init(ip);

	if(err != ctr_ok)
	{
		delete p;
		g_Handlemap.erase(*handle);
	}

	return err;
}
ctr_error_t _stdcall CTR_SetCommPeriod(uint32_t handle,uint32_t iPeriod)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->SetCommPeriod(iPeriod) : (ctr_bad_handle);
}
ctr_error_t _stdcall CTR_Close(uint32_t handle)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->Stop() : (ctr_bad_handle);
}
ctr_error_t _stdcall CTR_Enable(uint32_t handle,EnableState enableState,uint64_t outputEnableBits)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->Enable(enableState,outputEnableBits) : (ctr_bad_handle);
}
ctr_error_t _stdcall CTR_IsEnabled(uint32_t handle,uint32_t * isenabled)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->IsEnabled(isenabled) : (ctr_bad_handle);
}

ctr_error_t _stdcall CTR_SetPWM(uint32_t handle,ctr_nodeType_t node,int param,int pwmChannel, int16_t pulseWidth)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->SetPWM(node,param,pwmChannel,pulseWidth) : (ctr_bad_handle);
}
ctr_error_t _stdcall CTR_GetADC(uint32_t handle,ctr_nodeType_t node,int param,int channel, uint32_t * result)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->GetADC(node,param,channel,result) : (ctr_bad_handle);
}
ctr_error_t _stdcall CTR_GetPosition(uint32_t handle,ctr_nodeType_t node,int param,int channel, uint32_t * result)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->GetPosition(node,param,channel,result) : (ctr_bad_handle);
}
ctr_error_t _stdcall CTR_GetVelocity(uint32_t handle,ctr_nodeType_t node,int param,int channel, uint32_t * result)
{	
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->GetVelocity(node,param,channel,result) : (ctr_bad_handle);
}    
ctr_error_t _stdcall CTR_SetSolenoid(uint32_t handle,ctr_nodeType_t node,int param,int channel, bool enable)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->SetSolenoid(node,param,channel,enable) : (ctr_bad_handle);
}    
ctr_error_t _stdcall CTR_SetRelay(uint32_t handle,ctr_nodeType_t node,int param,int channel, unsigned char state)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->SetRelay(node,param,channel,state) : (ctr_bad_handle);
}   

ctr_error_t _stdcall CTR_GetGPIO(uint32_t handle,ctr_nodeType_t node,int param, uint32_t * result)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->GetGPIO(node,param,result) : (ctr_bad_handle);
} 

ctr_error_t _stdcall CTR_SetActiveRcmNodeId(uint32_t handle,int nodeId)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->SetActiveRcmNodeid(nodeId) : (ctr_bad_handle);
}

ctr_error_t _stdcall CTR_SetFilter(	uint32_t handle,
								unsigned int iFilterIdx,
								const CANFrame_t * pMsgData,
								const CANFrame_t * pMsgMask)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->SetFilter(iFilterIdx,pMsgData,pMsgMask) : (ctr_bad_handle);
}  

ctr_error_t _stdcall CTR_ClearFilter(	uint32_t handle,
										unsigned int iFilterIdx)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->ClearFilter(iFilterIdx) : (ctr_bad_handle);
}


ctr_error_t _stdcall CTR_GetFrames(	uint32_t handle,
									CANFrame_t * frames,
									uint32_t capacity,
									uint32_t * num_msgs)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->GetFrames(frames,capacity,num_msgs) : (ctr_bad_handle);
}

ctr_error_t _stdcall CTR_SendFrames(uint32_t handle,
									const CANFrame_t * frames,
									uint32_t num_msgs)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->SendFrames(frames,num_msgs) : (ctr_bad_handle);
}

ctr_error_t _stdcall CTR_GetCommStats(	uint32_t handle,
										CommStats * stats)
{
	P2CANClient cl( GetClient(handle) );
	return (cl) ? cl->GetCommStats(stats) : (ctr_bad_handle);
}



ctr_error_t _stdcall CTR_GetDllVersion(uint32_t *version)
{
	//return ctr_not_implemented;
	if(!version)
		return ctr_badParameter;

	const TCHAR dllName[] = _T("2CAN_Comm.dll");
    DWORD dllHandle,size;

	size = GetFileVersionInfoSize(dllName, &dllHandle);
	if(size > 5*1024)
		return ctr_fail;

	if(GetFileVersionInfo == 0)
		return ctr_fail;

	uint8_t * info = new unsigned char[size];
	GetFileVersionInfo(dllName, dllHandle, size, info);

	uint8_t *bytesFileInfo = 0;
	uint32_t Length;
	VerQueryValue(info, _T("\\"), (void **)&bytesFileInfo, &Length);

	VS_FIXEDFILEINFO * fixedFileInfo = (VS_FIXEDFILEINFO *)bytesFileInfo;

	uint32_t &vers = *version;
	vers = (uint8_t)(fixedFileInfo->dwFileVersionMS >> 0x10);
	vers <<= 8;
	vers |= (uint8_t)(fixedFileInfo->dwFileVersionMS >> 0x00);
	vers <<= 8;
	vers |= (uint8_t)(fixedFileInfo->dwFileVersionLS >> 0x10);
	vers <<= 8;
	vers |= (uint8_t)(fixedFileInfo->dwFileVersionLS >> 0x00);

	delete info;
	info = 0;

	return ctr_ok;
}